using System;
using NUnit.Framework;
using SpecMaker.Core.Assertions;
using SpecMaker.Core.Exceptions;

namespace SpecMaker.UnitTests
{

    [TestFixture]
    public class SpecAssertsWhenComparingIntAndShouldEqual
    {
        [Test]
        public void two_equal_numbers_should_not_throw_exception()
        {
            11.ShouldEqual(11);
        }
        [Test]
        public void two_non_equal_numbers_should_throw_assertion_exception()
        {
            try
            {
                11.ShouldEqual(12);
                Assert.Fail("should fail if we get here because there should be an exception");
            }
            catch (RuleException)
            {
            }
        }
        [Test]
        public void two_non_equal_numbers_should_display_friendly_message()
        {
            try
            {
                11.ShouldEqual(12);

            }
            catch (RuleException ex)
            {
                StringAssert.Contains("The expected value of 11 was actually 12.", ex.Message);
            }
        }
    }
    [TestFixture]
    public class SpecAssertsWhenComparingIntAndNotEqual
    {
        [Test]
        public void should_not_throw_assertion_exception()
        {
            11.ShouldNotEqual(12);
        }

        [Test]
        public void two_equal_numbers_should_throw_assertion_exception()
        {
            try
            {
                11.ShouldNotEqual(11);
                Assert.Fail();
            }
            catch (RuleException)
            {
            }
        }
        [Test]
        public void two_equal_numbers_should_display_friendly_error_message()
        {
            try
            {
                11.ShouldNotEqual(11);
            }
            catch (RuleException ex)
            {
                StringAssert.Contains("The two values incorrectly equal one another. The number was 11", ex.Message);
            }
        }
    }
    [TestFixture]
    public class SpecAssertsWhenComparingDoublesAndShouldBeEqual
    {
        const double DBL_ACTUAL_WITH_FLOAT = (2.0 + (2.0/3.0));
        const double DBL_ACTUAL_WHOLE_BIG = 640000.0;
        const double DBL_EXPECTED_WHOLE_CALC = 800*800; 
        const double DBL_EXPECTED_WITH_FLOAT =2.6666666666667;
        const double DBL_VARIANT = 4.66666668;
        const double TOLERANCE = .000000000001;

        [Test]
        public void two_equal_large_double_numbers_should_compare_equal()
        {
            DBL_EXPECTED_WHOLE_CALC.DoubleIsEqualWithTolerance(DBL_ACTUAL_WHOLE_BIG, TOLERANCE);
        }

        [Test]
        public void two_equal_double_float_numbers_should_compare_equal()
        {
            DBL_EXPECTED_WITH_FLOAT.DoubleIsEqualWithTolerance(DBL_ACTUAL_WITH_FLOAT, TOLERANCE);
            
        }
        [Test]
        public void two_non_equal_double_numbers_should_throw_error_assertion()
        {
            try
            {

                DBL_EXPECTED_WITH_FLOAT.DoubleIsEqualWithTolerance(DBL_VARIANT,TOLERANCE);
                Assert.Fail();
            }
            catch (RuleException)
            {
               

            }
        }

        [Test]
        public void two_non_equal_double_numbers_should_display_friendly_error_message()
        {
            try {
                DBL_EXPECTED_WITH_FLOAT.DoubleIsEqualWithTolerance(DBL_VARIANT, TOLERANCE);

            }
            catch (RuleException ex) {
                StringAssert.Contains("The two double numbers were not equal within a tolerable level of 1E-12", ex.Message);
            }
        }
    }
    [TestFixture]
    public class SpecAssertsWhenComparingStringAndStartingValue
    {
        const string CONTENT_GIVEN = "Jon Jacob";
        [Test]
        public void should_not_throw_assertion_exception()
        {
            CONTENT_GIVEN.ShouldStartWith("Jon ");
        }
        [Test]
        public void string_does_not_start_with_value_should_throw_rule_exception()
        {
            try
            {
                CONTENT_GIVEN.ShouldStartWith("Jacob");
                Assert.Fail();
            }
            catch (RuleException)
            {
            }
        }
        [Test]
        public void string_does_not_start_with_value_should_display_descriptive_error_message()
        {
            try
            {
                CONTENT_GIVEN.ShouldStartWith("Jacob");
            }
            catch (RuleException ex)
            {
                StringAssert.Contains("The actual starting value is different than the expected text. The expected text was Jacob and the actual text is Jon Jacob", ex.Message);
            }
        }
    }
    [TestFixture]
    public class SpecAssertsWhenComparingStringAndContainingContent
    {
        const string CONTENT_GIVEN = "The large fox could not jump over the fence.";

        [Test]
        public void should_not_throw_assertion_exception()
        {
            CONTENT_GIVEN.ShouldContain("fox");
        }

        [Test]
        public void string_is_not_contained_within_the_expected_text()
        {
            try
            {
                CONTENT_GIVEN.ShouldContain("tomahawk");
                Assert.Fail();
            }
            catch (RuleException)
            {

            }
        }
        [Test]
        public void string_is_not_contained_within_the_expected_text_displays_a_descriptive_error_message()
        {
            try
            {
                CONTENT_GIVEN.ShouldContain("tomahawk");
            }
            catch (RuleException ex)
            {
                StringAssert.Contains("The actual containing text value is different than the expected text. The expected text of tomahawk was not found", ex.Message);
            }
        }
    }
    [TestFixture]
    public class SpecAssertsWhenComparingStringAndEndingValue
    {
        const string CONTENT_GIVEN = "The account is now considered delinquent.";

        [Test]
        public void should_not_throw_assertion_exception()
        {
            CONTENT_GIVEN.ShouldEndWith("delinquent.");
        }

        [Test]
        public void string_does_not_end_with_the_expected_text()
        {
            try
            {
                CONTENT_GIVEN.ShouldEndWith("standing.");
                Assert.Fail();
            }
            catch (RuleException)
            {

            }
        }
        [Test]
        public void string_does_not_end_with_the_expected_text_displays_a_descriptive_error_message()
        {
            try
            {
                CONTENT_GIVEN.ShouldEndWith("standing.");
            }
            catch (RuleException ex)
            {
                StringAssert.Contains("The actual ending text value is different than the expected text. The expected text of standing. was not found", ex.Message);
            }
        }
    }

}